package app.conn;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;

import app.Main;
import app.gui.SetupDialog;

/**
 * Greenhouse WebDB connector 
 * 
 * using HttpConnector to communicate over HTTP protocol
 * with POST request method
 * 
 * 
 * @author Lukas Vavra
 *
 */
public class WebDB {
	private static final String OK = "<ok>";
	private static final String FAIL = "<fail>";
	private static final String USR_EXIST = "<usrexist>";

	private static HttpConnector http;

	/**
	 *  Create instance of HttpConnector for perform communication with Greenhouse server
	 *  
	 * @throws IOException Connection failed, server isn't reachable
	 */
	public static void init() throws IOException {
		if(http == null)
			if(Main.appcnf.getServer() == null) {
				new SetupDialog(null);
				init();
				return;
			}
		http = new HttpConnector(Main.appcnf.getServer());
	}

	/**
	 * Check token and connection
	 * 
	 * @param token User unique token
	 * @return True, if connection and token are OK
	 * @throws IOException Connection error, server is not responding
	 */
	public static boolean check(String token, String username) throws IOException {
		init();
		String[] param = new String[3];

		param[0] = "token=".concat(token);
		param[1] = "user=".concat(username);
		param[2] = "action=check";

		http.send(param);

		String[] result = http.receive();

		if(result != null && result.length > 0 && result[0].equals(OK)) {
			return true;
		}

		return false;		
	}


	/**
	 * Login to server interface
	 * 
	 * @param user User name
	 * @param pass User password
	 * @return Generated token for next communication if logged in, else return null
	 * @throws IOException Connection error, server is not responding
	 */
	public static String login(String user, String pass) throws IOException {
		init();
		String[] param = new String[3];

		try {
			param[0] = "user=".concat(user);
			param[1] = "pass=".concat(HttpConnector.md5(pass));
			param[2] = "action=login";

			http.send(param);

			String[] result = http.receive();

			if(result != null && result.length > 0 && result[0].equals(OK)) {
				return result[1];
			}
		} catch (NoSuchAlgorithmException e) {
			Main.showError("Chyba algoritmu", e.toString());
			System.exit(-1);
		}


		return null;
	}

	/**
	 * Register new user
	 * 
	 * @param user User name
	 * @param pass User password (in naked string format)
	 * @return Generated token for next communication if logged in, else return null
	 * @throws IOException Connection error, server is not responding
	 */
	public static String register(String user, String pass) throws IOException {
		init();
		String[] param = new String[3];

		try {
			param[0] = "user=".concat(user);
			param[1] = "pass=".concat(HttpConnector.md5(pass));
			param[2] = "action=register";

			http.send(param);

			String[] result = http.receive();
			if(result != null && result.length > 0) {
				if(result[0].equals(OK)) {
					return result[1];
				}
				else if(result[0].equals(USR_EXIST)) {
					Main.showError("Chybné uživatelské jméno", "Uživatel již existuje");
					return null;
				}
				else if(result[0].equals(FAIL)) {
					Main.showError("Chyba serveru", result[1]);
					return null;
				}
				else {
					Main.showError("Neznámá chyba", "");
					return null;
				}

			}
		} catch (NoSuchAlgorithmException e) {
			Main.showError("Chyba algoritmu", e.toString());
			return null;
		}
		return null;
	}

	/**
	 * Get list of all connected units with unit name and unit id 
	 * 
	 * @return unit-id unit-name pairs stored in String array String[0] = "1 name";
	 * @throws IOException Connection error, server is not reachable
	 */
	public static String[] getUnitList() throws IOException {
		init();
		/* check that user is logged in */
		if(!Main.isLogged()) {
			Main.showError("Chyba přihlášení", "Nepřihlášený uživatel");
			return null;
		}

		/* prepare request */
		String[] param = new String[2];
		param[0] = "token=".concat(Main.getToken());
		param[1] = "action=unitlist";

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				return result;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return null;
			}
		}

		return null;
	}

	/**
	 * Add new unit into webDB
	 * 
	 * @param name Unit name
	 * @return Communication token for new greenhouse unit, null if error
	 * @throws IOException Connection error, server is not responding
	 */
	public static String[] addUnit(String name) throws IOException {
		init();
		/* check that user is logged in */
		if(!Main.isLogged()) {
			Main.showError("Chyba přihlášení", "Nepřihlášený uživatel");
			return null;
		}

		/* prepare request */
		String[] param = new String[3];
		param[0] = "token=".concat(Main.getToken());
		param[1] = "unitname=".concat(name);
		param[2] = "action=addunit";

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				return result;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return null;
			}
		}
		return null;
	}

	/**
	 * Get Server info
	 * 
	 * @return String array with server infos
	 * @throws IOException Connection error, server is not responding
	 */
	public static String[] getInfo() throws IOException {
		init();

		/* prepare request */
		String[] param = new String[1];
		param[0] = "action=getinfo";

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				return result;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return null;
			}
		}
		return null;
	}


	/**
	 * Remove unit from webDB
	 * 
	 * @param unitid Unit identifier in webDB
	 * @return Remove result - true if unit successfully removed
	 * @throws IOException Connection error, server is not responding
	 */
	public static boolean removeUnit(String unitid) throws IOException {
		init();
		/* check that user is logged in */
		if(!Main.isLogged()) {
			Main.showError("Chyba přihlášení", "Nepřihlášený uživatel");
			return false;
		}

		/* prepare request */
		String[] param = new String[3];
		param[0] = "token=".concat(Main.getToken());
		param[1] = "unitid=".concat(unitid);
		param[2] = "action=removeunit";

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				return true;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return false;
			}
		}
		return false;
	}

	/**
	 * Get records from WebDB 
	 * 
	 * @param unitid Unit identifier in WebDB
	 * @return Array of record strings
	 * @throws IOException Connection error, server is not reachable
	 * @throws ParseException Input data format error
	 */
	public static String[] getRecords(String unitid) throws IOException, ParseException {
		init();
		/* check that user is logged in */
		if(!Main.isLogged()) {
			Main.showError("Chyba přihlášení", "Nepřihlášený uživatel");
			return null;
		}

		/* prepare request */
		String[] param = new String[3];
		param[0] = "token=".concat(Main.getToken());
		param[1] = "unitid=".concat(unitid);
		param[2] = "action=getrec";

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				/* reformat input data */
				SimpleDateFormat input = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				SimpleDateFormat output = new SimpleDateFormat("HHmmssyyyyMMdd");
				String[] rec = new String[result.length - 1];
				String[] splited;
				String time;

				for(int i = 1; i < result.length; i++) {
					splited = result[i].split(" ");
					time = output.format(input.parse(splited[1].concat(" ").concat(splited[2])));

					if(splited[0].equals("E")) {
						rec[i - 1] = splited[0].concat(time).
								concat(String.format("%02d", Integer.parseInt(splited[3]))).
								concat(String.format("%03d", Integer.parseInt(splited[4]))).
								concat(String.format("%03d", Integer.parseInt(splited[5])));
					}
					else if(splited[0].equals("A")){
						rec[i - 1] = splited[0].concat(time).concat(splited[3]).
								concat(splited[4]).concat(splited[5]);
					}
				}
				/* return data */				
				return rec;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return null;
			}
		}

		return null;
	}

	/**
	 * Get config data from WebDB 
	 * 
	 * @param unitid Unit identifier in WebDB
	 * @return Array of config strings
	 * @throws IOException Connection error, server is not reachable
	 */
	public static String[] getConfig(String unitid) throws IOException {
		init();
		/* check that user is logged in */
		if(!Main.isLogged()) {
			Main.showError("Chyba přihlášení", "Nepřihlášený uživatel");
			return null;
		}

		/* prepare request */
		String[] param = new String[3];
		param[0] = "token=".concat(Main.getToken());
		param[1] = "unitid=".concat(unitid);
		param[2] = "action=getcnf";

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				String[] cnf = new String[result.length - 1];
				cnf = Arrays.copyOfRange(result, 1, result.length);
				return cnf;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return null;
			}
		}

		return null;
	}

	/**
	 * Clear all config data for selected unit
	 * 
	 * @param unitid Unit identifier in WebDB
	 * @return True, if request successfully sent
	 * @throws IOException Connection error, server is not reachable
	 */
	public static boolean clearConfig(String unitid) throws IOException {
		init();
		/* check that user is logged in */
		if(!Main.isLogged()) {
			Main.showError("Chyba přihlášení", "Nepřihlášený uživatel");
			return false;
		}

		/* prepare request */
		String[] param = new String[3];
		param[0] = "token=".concat(Main.getToken());
		param[1] = "unitid=".concat(unitid);
		param[2] = "action=clearcnf";

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				return true;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return false;
			}
		}

		return false;
	}

	/**
	 * Clear all records for selected unit in db
	 * 
	 * @param unitid Unit identifier in WebDB
	 * @return True, if request successfully sent
	 * @throws IOException Connection error, server is not reachable
	 */
	public static boolean clearRecords(String unitid) throws IOException {
		init();
		/* check that user is logged in */
		if(!Main.isLogged()) {
			Main.showError("Chyba přihlášení", "Nepřihlášený uživatel");
			return false;
		}

		/* prepare request */
		String[] param = new String[3];
		param[0] = "token=".concat(Main.getToken());
		param[1] = "unitid=".concat(unitid);
		param[2] = "action=clearrec";

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				return true;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return false;
			}
		}
		return false;
	}

	/**
	 * Send configuration data for selected unit into DB
	 * 
	 * @param unitid Unit identifier in WebDB
	 * @param data Config data line
	 * @return True, if request successfully sent
	 * @throws IOException Connection error, server is not reachable
	 */
	public static boolean sendConfig(String unitid, String data) throws IOException {
		init();
		/* check that user is logged in */
		if(!Main.isLogged()) {
			Main.showError("Chyba přihlášení", "Nepřihlášený uživatel");
			return false;
		}

		/* prepare request */
		String[] param = new String[4];
		param[0] = "token=".concat(Main.getToken());
		param[1] = "unitid=".concat(unitid);
		param[2] = "action=sendcnf";
		param[3] = "data=".concat(data);

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				return true;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return false;
			}
		}
		return false;
	}

	/**
	 * Set update config flag for selected unit
	 * 
	 * @param unitid Unit identifier in WebDB
	 * @return True, if request successfully sent
	 * @throws IOException Connection error, server is not reachable
	 */
	public static boolean setUpdateConfig(String unitid) throws IOException {
		init();
		/* check that user is logged in */
		if(!Main.isLogged()) {
			Main.showError("Chyba přihlášení", "Nepřihlášený uživatel");
			return false;
		}

		/* prepare request */
		String[] param = new String[3];
		param[0] = "token=".concat(Main.getToken());
		param[1] = "unitid=".concat(unitid);
		param[2] = "action=updatecnf";

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				return true;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return false;
			}
		}
		return false;
	}

	/**
	 * Set request config flag for selected unit
	 * 
	 * @param unitid Unit identifier in WebDB
	 * @return True, if request successfully sent
	 * @throws IOException Connection error, server is not reachable
	 */
	public static boolean setRequestConfig() throws IOException {
		init();
		/* check that user is logged in */
		if(!Main.isLogged()) {
			Main.showError("Chyba přihlášení", "Nepřihlášený uživatel");
			return false;
		}

		/* prepare request */
		String[] param = new String[3];
		param[0] = "token=".concat(Main.getToken());
		param[2] = "action=requestcnf";

		/* send a request and get a response */
		http.send(param);
		String[] result = http.receive();

		/* verify received data */
		if(result != null && result.length > 0) {
			if(result[0].equals(OK)) {
				return true;
			}
			else if(result[0].equals(FAIL)) {
				Main.showError("Chyba serveru", result[1]);
				return false;
			}
		}
		return false;
	}
}
